package net.intellect.collectpro.gestores;

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import com.sforce.soap.enterprise.ID;
import com.sforce.soap.enterprise.sobject.Cobro__c;
import com.sforce.soap.enterprise.sobject.Llamada__c;
import com.sforce.soap.enterprise.sobject.SObject;

import net.intellect.collectpro.objects.Cartera;
import net.intellect.collectpro.objects.Empresa;
import net.intellect.collectpro.objects.Llamada;
import net.intellect.collectpro.objects.Mora;
import net.intellect.collectpro.util.ComparatorPeso;
import net.intellect.collectpro.util.Parametros;
import net.intellect.collectpro.util.Util;
import net.intellect.force.UtilBasic;


public class MarcadorPredictivo extends GestorSalesforce {
	String rutaArchivo = "";
	int diasMas = 0;
	double tipoCambio = 1;
	
	public MarcadorPredictivo(String user,String password,String token,String codEmpresa,double tipoCambio,String rutaArchivo,int diasMas,boolean isSandBox,String urlProxy,String puertoProxy) {
		super(user, password, token, codEmpresa,isSandBox,urlProxy,puertoProxy);
		this.rutaArchivo = rutaArchivo;
		this.diasMas = diasMas;
		this.tipoCambio = tipoCambio;		
		Parametros.TIPO_CAMBIO =this.tipoCambio; 			
	}	

	
	public void generarArchivosMP() {
		try {
			Empresa empresa = this.obtenerConfiguracionEmpresa(codEmpresa);
			if (empresa!=null) {
				logger.info("Empresa: " + empresa.getName() + ".");
				for (Cartera cartera:empresa.getCarteras()) {
					for (Mora mora:cartera.getMoras()) {
						if (mora.isMarcadorPredictivo()) {
							//Genera archivo de mora
							try {
								this.escribirArchivoMP(empresa.getId(), mora);
							} catch (Exception e) {
								logger.error("Error generando el archivo para la mora " + mora.getNombre());
								logger.error(e);
							}							
						}
					}
				}
			}
		} catch (Exception e) {
			logger.error(e);
		}		
	}
	
	/**
	 * Escribe en disco el archivo para el marcador predictivo
	 * @param idEmpresa
	 * @param mora
	 * @param ruta
	 * @param diasMas
	 * @throws Exception
	 */
	protected void escribirArchivoMP(ID idEmpresa,Mora mora) throws Exception {
		try {
			
			Map<String,Integer>  mapIdsLlamadas = this.obtenerIdsLlamadas(idEmpresa,mora.getId());
			
			
			List<Llamada> llamadasTemp = this.obtenerCobrosMPByMora(mapIdsLlamadas,mora.getId());
			logger.info("Mora = " + mora.getNombre());
			logger.debug("	Total de cobros MP = " + llamadasTemp.size());
			
			//Separa la lista de llamadas (Crea los grupos vacios y luego distribuye)
			List<List<Llamada>> gruposLlamadas = new ArrayList<List<Llamada>>();		
			for (int i=0;i<=Llamada.PESO_DEFAULT;i++) {
				List<Llamada> llamadas = new ArrayList<Llamada>();
				gruposLlamadas.add(llamadas);
			}
			for (Llamada llamadaTemp:llamadasTemp) {				
				gruposLlamadas.get(llamadaTemp.getPeso()).add(llamadaTemp);
			}
			
			//Abre un archivo			
			PrintWriter escribir = new PrintWriter(new BufferedWriter(new FileWriter(rutaArchivo + System.getProperty("file.separator") +  "marcador" + mora.getNombre() + ".txt")));
			int indexCobro = llamadasTemp.size();
			for (List<Llamada> llamadas:gruposLlamadas) { 
				Collections.sort(llamadas,new ComparatorPeso());
				logger.info("		Total de cobros MP = " + llamadas.size());	
				for (Iterator<Llamada> iter=llamadas.iterator();iter.hasNext();) {
					Llamada__c llamada = iter.next().getLlamada__c();
					
					String linea = new String();
					linea += Util.completarString(llamada.getCobro__c().getID(),18);
					//linea += Util.completarString(llamada.getCobro__r().getUltimo_Codigo_Resultado__c() + "  ",18);
					
					if (llamada.getCuenta__r()!=null) {
						linea += Util.completarStringDerecha(llamada.getCuenta__r().getTC_Telefono_Celular__c(),20);
						linea += Util.completarStringDerecha(llamada.getCuenta__r().getTC_Telefono_Casa__c(),20);
						linea += Util.completarStringDerecha(llamada.getCuenta__r().getTC_Telefono_Trabajo__c(),20);
						
						linea += Util.completarStringDerecha(llamada.getCuenta__r().getMP_Telefono_Trabajo__c(),20);
						linea += Util.completarStringDerecha(llamada.getCuenta__r().getMP_Telefono_Casa__c(),20);
						linea += Util.completarStringDerecha(llamada.getCuenta__r().getMP_Telefono_Celular__c(),20);					
					} else {
						linea += Util.completarString("",20);
						linea += Util.completarString("",20);
						linea += Util.completarString("",20);
						linea += Util.completarString("",20);
						linea += Util.completarString("",20);
						linea += Util.completarString("",20);					
					}
					
					
									
					linea += Util.completarString("HN",10);
					linea += Util.formatearNum(indexCobro--,6,0);
					
					
					if (llamada.getCobro__r()!=null) {
						linea += Util.formatearNum(llamada.getCobro__r().getTC_Nivel_Mora_Consolidado__c(),3,0);						
						linea += Util.formatearNum(llamada.getCobro__r().getTC_Pago_Minimo_Local__c(),16,2);
						linea += Util.formatearNum(llamada.getCobro__r().getTC_Pago_Minimo_USD__c(),16,2);
					} else {
						linea += Util.formatearNum(0,3,0);						
						linea += Util.formatearNum(0,16,2);
						linea += Util.formatearNum(0,16,2);						
					}
					
					
					
					if (llamada.getCuenta__r()!=null) {
						linea += Util.completarStringDerecha(llamada.getCuenta__r().getName(),60);
					} else {
						linea += Util.completarString("",60);
					}
					
					//Numero de tarjeta
					if (llamada.getTarjeta__r()!=null) {
						linea += Util.completarString(llamada.getTarjeta__r().getNumero_Tarjeta__c(),20);						
					} else {
						linea += Util.completarString("",20);						
					}					
					
					//Tipo de producto
					if (llamada.getInfo_Cuenta__r()!=null) {						
						linea += Util.completarString(llamada.getInfo_Cuenta__r().getTC_Codigo_Producto__c(),20);					
						
					} else {
						linea += Util.completarString("",20);						
					}				
					
					if (llamada.getCobro__r()!=null) {
						linea += Util.formatearNum(llamada.getCobro__r().getTC_Nivel_Mora_Local__c(),8,0);
						linea += Util.formatearNum(llamada.getCobro__r().getTC_Nivel_Mora_USD__c(),8,0);						
					} else {
						linea += Util.formatearNum(0,8,0);
						linea += Util.formatearNum(0,8,0);											
					}
					
					if (llamada.getInfo_Cuenta__r()!=null) {
						linea += Util.formatearNum(llamada.getInfo_Cuenta__r().getTC_Saldo_Actual_Local__c(),16,2);
						linea += Util.formatearNum(llamada.getInfo_Cuenta__r().getTC_Saldo_Actual_USD__c(),16,2);
					} else {
						linea += Util.formatearNum(0 ,16,2);
						linea += Util.formatearNum(0 ,16,2);					
					}
						
					escribir.println(linea);
				}
			}
			escribir.close();
			
			
		} catch (Exception e) {
			logger.error(e);
			throw e;		
		}
	}
	
	
	/**
	 * Obtiene la lista de llamdas del marcador predictivo
	 * @param idMora
	 * @return
	 * @throws Exception
	 */
	protected List<Llamada> obtenerCobrosMPByMora(Map<String,Integer> idsLlamadas,ID idMora) throws Exception{

		List<Llamada> llamadas = new ArrayList<Llamada>();

		String sql =			
					"Select " +
						"l.Tarjeta__r.Numero_Tarjeta__c, l.Info_Cuenta__r.TC_Codigo_Producto__c, " +
						"l.Tarjeta__c, l.Id, l.Cuenta__r.TC_Telefono_Celular__c, " +
						"l.Cuenta__r.TC_Telefono_Trabajo__c, l.Cuenta__r.TC_Telefono_Casa__c, " +
						"l.Cuenta__r.MP_Telefono_Trabajo__c, l.Cuenta__r.MP_Telefono_Celular__c, l.Cuenta__r.MP_Telefono_Casa__c, " +
						"l.Cuenta__r.Name, l.Cuenta__c, l.Cobro__r.TC_Nivel_Mora_Consolidado__c, " +
						"l.Cobro__r.TC_Nivel_Mora_USD__c, l.Cobro__r.TC_Nivel_Mora_Local__c, " +
						"l.Cobro__r.TC_Pago_Minimo_USD__c, l.Cobro__r.TC_Pago_Minimo_Local__c, " +
						"l.Cobro__r.TC_Pago_Contado_USD__c, l.Cobro__r.TC_Pago_Contado_Local__c, " +
						"l.Info_Cuenta__r.TC_Saldo_Actual_USD__c, l.Info_Cuenta__r.TC_Saldo_Actual_Local__c, " +
						"l.Cobro__c,l.Name,l.Cobro__r.Ultimo_Codigo_Resultado__c,Fecha_Agendada__c,l.Info_Cuenta__r.Score__c  " +								
					"From Llamada__c l " +
					"Where " +
					"Cobro__r.Conf_Info_Mora__c = '" + idMora + "' and " +
					"ID IN " ;
				
		List<SObject> objects = this.getObjectsByMapSalesforce(sql,idsLlamadas);
		
		if (objects!=null) {
			for (SObject object:objects) {
				llamadas.add(new Llamada((Llamada__c)object));
			}
		} 
		return llamadas;				
	}
	
	/**
	 * Retorna los ids de las llamadas que deben ser incluidas en el archivo del marcador predictivo
	 * @param idEmpresa
	 * @param idMora
	 * @return Mapa de ids de llamadas
	 * @throws Exception
	 */
	Map<String,Integer> obtenerIdsLlamadas(ID idEmpresa,ID idMora) throws Exception{
		List<SObject> objects = new ArrayList<SObject>();
		Map<String,Integer>  mapIdsLlamadas = new HashMap<String,Integer>();
		Date fechaInicial = new Date();
		String sql;
		
		try {
			if (diasMas>0) {
				String[] codigosExcentos = {"PRO","POP","CSP","CDP"};
				Date fechaFinal = Util.sumarDiasFecha(fechaInicial, diasMas);
				
				// Consulta el id de las llamadas que debe tomar en cuenta para generar el archivo
				sql =
					"Select l.Id From Llamada__c l " +
					"Where "+ 
					"l.Empresa_del_grupo__c = '" + idEmpresa + "' and  " +
					"l.Codigo_Resultado__c  ='PEN' and " +
					"IsMarcadorPredictivo__c = true and "+ 
					"(" +
					"(l.Fecha_Agendada__c <= " + UtilBasic.obtenerDateSalesforce(fechaInicial) + ") or " +
					"(l.Fecha_Agendada__c > " + UtilBasic.obtenerDateSalesforce(fechaInicial) + 
					" and l.Fecha_Agendada__c <= " + UtilBasic.obtenerDateSalesforce(fechaFinal);
				for (int i=0; i<codigosExcentos.length;i++){
					sql += " and l.Cobro__r.Ultimo_Codigo_Resultado__c != '"+ codigosExcentos[i] + "'";
				}
				sql += "))";
				objects = this.getObjectsSalesforce(sql);
				
				if (objects != null) {
					for (SObject object:objects) {
						Llamada__c llamada = (Llamada__c)object; 
						mapIdsLlamadas.put(llamada.getId().getID(), 0);
					}
				}
			} 
			if (diasMas<= 0) {
				fechaInicial = Util.sumarDiasFecha(fechaInicial, diasMas);
				// Consulta todos los codigos
				sql =
					"Select " +
					"id " +								
				"From Llamada__c l " +
				"Where " +
				"l.Empresa_del_grupo__c = '" + idEmpresa + "' and " +  
				"l.Codigo_Resultado__c  ='" + "PEN" + "' and  l.Fecha_Agendada__c <= " + UtilBasic.obtenerDateSalesforce(fechaInicial) + " and " +
				"IsMarcadorPredictivo__c = true  " ; 			
				objects = this.getObjectsSalesforce(sql);
				
				if (objects!=null) {
					for (SObject object:objects) {
						Llamada__c llamada = (Llamada__c)object; 
						mapIdsLlamadas.put(llamada.getId().getID(), 0);
					}
				} 
			}
		
			 
			
		} catch(Exception e) {
			System.out.println(e);
		}
		
		return mapIdsLlamadas;
	}
	
	public void actualizarCodigoResultadoCobro() {
		
		try {
			Empresa empresa = this.obtenerConfiguracionEmpresa(codEmpresa);
			
			String sql =
				"Select " +
				"id,Cobro__c " +								
			"From Llamada__c l " +
			"Where " +
			"l.Empresa_del_grupo__c = '" + empresa.getId() + "' and " +  
			//"l.Codigo_Resultado__c  ='" + "PEN" + "' and Fecha_Agendada__c > TOMORROW and Cobro__r.Conf_Info_Mora__c = 'a0T5000000AK60ZEAT' " ; 			
			//"l.Codigo_Resultado__c  ='" + "PEN" + "' and Cobro__r.Ultimo_Codigo_Resultado__c = ''  and Cobro__r.Conf_Info_Mora__c = 'a0T5000000AK60ZEAT' " ;
			"l.Codigo_Resultado__c  ='" + "PEN" + "'  and Cobro__r.Conf_Info_Mora__c != 'a0T5000000AK60ZEAT' " ;
					
			List<SObject> objects = this.getObjectsSalesforce(sql);

			List<Cobro__c> cobros = new ArrayList<Cobro__c>();
			if (objects!=null) {
				for (SObject object:objects) {
					Llamada__c llamada = (Llamada__c)object;
					Cobro__c cobro = new Cobro__c();
					cobro.setId(llamada.getCobro__c());
					String sql2 =
						"Select Codigo_Resultado__c From Llamada__c Where Cobro__c = '" + llamada.getCobro__c() + "' and " +
						" Id !='" + llamada.getId() +"' order by CreatedDate desc Limit 1";					
					
					SObject object2 = this.getObjectSalesforce(sql2);							
					cobro.setUltimo_Codigo_Resultado__c("");
					if (object2!=null && ((Llamada__c)(object2)).getCodigo_Resultado__c()!=null) {
						cobro.setUltimo_Codigo_Resultado__c(((Llamada__c)(object2)).getCodigo_Resultado__c());
					}
					cobros.add(cobro);
				}	
			} 
			actualizarRegistros(cobros);
		} catch (Exception e) {
			logger.error(e);
			// TODO: handle exception
		}
					
	}

}
